package apps.kine.android.traxxsalon;

import java.util.Calendar;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TimePicker;

public class QuickBookingActivity extends Activity implements OnClickListener {
	private static final String TAG = "QuickBookingActivity";

	// Views
	private EditText mNameField;
	private TextView mDateDisplay;
	private TextView mTimeDisplay;
	private EditText mPhoneNumberField;

	// Attributes for the date
	private int mYear;
	private int mMonth;
	private int mDay;

	// Attributes for the time
	private int mHour;
	private int mMinute;

	// Dialogs
	static final int DATE_DIALOG_ID = 0;
	static final int TIME_DIALOG_ID = 1;

	private static final int ERRORCODE_INVALID_NAME = 0;
	private static final int ERRORCODE_DAY_OFF = 1;
	private static final int ERRORCODE_SHOP_CLOSED = 2;
	private static final int ERRORCODE_INVALID_DATETIME = 3;

	private static final int MINIMUM_HOURS_INTERVAL = 2;
	private static final int MINIMUM_MILLIS_INTERVAL = 7200000;

	private static final int OPENING_HOUR = 11;
	private static final int CLOSING_HOUR = 18;
	private static final int WEEKEND_CLOSING_HOUR = 21;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.quickbooking);

		mNameField = (EditText) findViewById(R.id.name);
		mDateDisplay = (TextView) findViewById(R.id.dateDisplay);
		mTimeDisplay = (TextView) findViewById(R.id.timeDisplay);
		mPhoneNumberField = (EditText) findViewById(R.id.phoneNumber);

		setDefaultDateTime();

		updateDisplay();
	}

	@Override
	public void onResume() {
		super.onResume();

		updateDisplay();
	}

	private void setDefaultDateTime() {
		// get the current date
		final Calendar c = Calendar.getInstance();
		mYear = c.get(Calendar.YEAR);
		mMonth = c.get(Calendar.MONTH);
		mDay = c.get(Calendar.DAY_OF_MONTH);

		final int minutes = c.get(Calendar.MINUTE);
		final boolean addHour = (minutes >= 30);

		final int hoursToAdd = addHour ? (MINIMUM_HOURS_INTERVAL + 1)
				: MINIMUM_HOURS_INTERVAL;
		final int hour = c.get(Calendar.HOUR_OF_DAY);
		c.set(Calendar.HOUR_OF_DAY, hour + hoursToAdd);

		c.set(Calendar.MINUTE, addHour ? 0 : 30);

		mHour = c.get(Calendar.HOUR_OF_DAY);
		mMinute = c.get(Calendar.MINUTE);
	}

	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.pickDateButton:
			// Open the date picker dialog
			showDialog(DATE_DIALOG_ID);
			break;

		case R.id.pickTimeButton:
			// Open the time picker dialog
			showDialog(TIME_DIALOG_ID);
			break;

		case R.id.bookNowButton:
			bookAppointment();
			break;

		default:
			break;
		}
	}

	private void bookAppointment() {
		int error = validate();
		int errorMsgId = -1;

		switch (error) {
		case -1:
			sendSMS();
			return;
		case ERRORCODE_INVALID_NAME:
			errorMsgId = R.string.error_invalidName;
			break;
		case ERRORCODE_DAY_OFF:
			errorMsgId = R.string.error_dayoff;
			break;
		case ERRORCODE_SHOP_CLOSED:
			errorMsgId = R.string.error_shopclosed;
			break;
		case ERRORCODE_INVALID_DATETIME:
			errorMsgId = R.string.error_invalidDateTime;
			break;
		default:
			return;
		}
		// Display the error message
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		if (error == ERRORCODE_SHOP_CLOSED) {
			String msg = new StringBuilder().append(getString(errorMsgId))
					.append('\n').append(getString(R.string.shop_hours))
					.toString();

			builder.setMessage(msg);
		} else {
			builder.setMessage(errorMsgId);
		}
		builder.setNegativeButton("OK", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int id) {
				dialog.cancel();
			}
		});
		AlertDialog errorAlert = builder.create();
		errorAlert.show();
	}

	private int validate() {
		if (mNameField.getText() == null || mNameField.getText().length() < 4) {
			return ERRORCODE_INVALID_NAME;
		}

		if (!isDateTimeValid()) {
			return ERRORCODE_INVALID_DATETIME;
		}

		int dayOfWeek = getDayOfWeek(mYear, mMonth, mDay);
		if (isDayOff(dayOfWeek)) {
			return ERRORCODE_DAY_OFF;
		}

		int hour = mHour;
		if (isShopClosed(dayOfWeek, hour)) {
			return ERRORCODE_SHOP_CLOSED;
		}

		return -1;
	}

	private int getDayOfWeek(final int aYear, int aMonth, int aDay) {
		final Calendar c = Calendar.getInstance();
		c.set(Calendar.YEAR, aYear);
		c.set(Calendar.MONTH, aMonth);
		c.set(Calendar.DAY_OF_MONTH, aDay);

		return c.get(Calendar.DAY_OF_WEEK);
	}

	private boolean isDateTimeValid() {
		final Calendar c = Calendar.getInstance();
		c.set(Calendar.YEAR, mYear);
		c.set(Calendar.MONTH, mMonth);
		c.set(Calendar.DAY_OF_MONTH, mDay);
		c.set(Calendar.HOUR_OF_DAY, mHour);
		c.set(Calendar.MINUTE, mMinute);

		Log.v("QBActivity", "Appt time " + c.getTimeInMillis());
		Log.v("QBActivity", "Curr time " + System.currentTimeMillis());
		if ((c.getTimeInMillis() - System.currentTimeMillis()) < MINIMUM_MILLIS_INTERVAL) {
			return false;
		}

		return true;
	}

	private boolean isDayOff(final int dayOfWeek) {
		if (dayOfWeek == Calendar.SUNDAY || dayOfWeek == Calendar.MONDAY) {
			return true;
		}
		return false;
	}

	private boolean isShopClosed(final int dayOfWeek, final int hour) {
		switch (dayOfWeek) {
		case Calendar.TUESDAY:
		case Calendar.WEDNESDAY:
		case Calendar.SATURDAY:
			if (hour < OPENING_HOUR || hour >= CLOSING_HOUR) {
				return true;
			}
			break;
		case Calendar.THURSDAY:
		case Calendar.FRIDAY:
			if (hour < OPENING_HOUR || hour >= WEEKEND_CLOSING_HOUR) {
				return true;
			}
			break;
		default:
			break;
		}
		return false;
	}

	private void sendSMS() {
		String smsText = new StringBuilder()
				.append(getString(R.string.appt_request)).append(" ")
				.append(mNameField.getText()).append(" on ")
				.append(mDateDisplay.getText()).append(" at ")
				.append(mTimeDisplay.getText()).append(".").toString();

		String phone = mPhoneNumberField.getText().toString();
		if (phone != null && phone.length() > 0) {
			smsText += " Call " + phone;
		}
		// Log.v(TAG, smsText);
		Intent smsIntent = new Intent(Intent.ACTION_VIEW, Uri.fromParts("sms",
				getString(R.string.phone_number), null));
		smsIntent.putExtra("sms_body", smsText);
		startActivity(smsIntent);

		finish();
	}

	private void updateDisplay() {
		updateDateDisplay();
		updateTimeDisplay();
	}

	private void updateDateDisplay() {
		mDateDisplay.setText(new StringBuilder()
				.append(getDayOfWeekString(getDayOfWeek(mYear, mMonth, mDay)))
				.append(", ").append(mDay).append(" ")
				.append(getMonthString(mMonth)).append(" ").append(mYear)
				.append(" "));
	}

	private String getDayOfWeekString(final int aDayOfWeek) {
		if (aDayOfWeek < 1 || aDayOfWeek > 7)
			return "";
		return getResources().getStringArray(R.array.dayofweek_array)[aDayOfWeek - 1];
	}

	private String getMonthString(final int aMonth) {
		if (aMonth < 0 || aMonth > 11)
			return "";
		return getResources().getStringArray(R.array.months_array)[aMonth];
	}

	private void updateTimeDisplay() {
		mTimeDisplay.setText(new StringBuilder().append(pad(mHour)).append(":")
				.append(pad(mMinute)));
	}

	private static String pad(int c) {
		if (c >= 10)
			return String.valueOf(c);
		else
			return "0" + String.valueOf(c);
	}

	// onCreateDialog
	@Override
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case DATE_DIALOG_ID:
			return new DatePickerDialog(this, mDateSetListener, mYear, mMonth,
					mDay);
		case TIME_DIALOG_ID:
			return new TimePickerDialog(this, mTimeSetListener, mHour, mMinute,
					false);
		}
		return null;
	}

	// DateSetListener
	private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() {
		public void onDateSet(DatePicker view, int year, int monthOfYear,
				int dayOfMonth) {
			mYear = year;
			mMonth = monthOfYear;
			mDay = dayOfMonth;
			updateDateDisplay();
		}
	};

	// TimeSetListener
	private TimePickerDialog.OnTimeSetListener mTimeSetListener = new TimePickerDialog.OnTimeSetListener() {
		public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
			mHour = hourOfDay;
			mMinute = minute;
			updateTimeDisplay();
		}
	};
}
